CM3D2 Converter.misc_OBJECT_PT_transform
1# 「プロパティ」エリア → 「オブジェクト」タブ → 「トランスフォーム」パネル 2import bpy 3import bmesh 4import mathutils 5import numpy as np 6from . import common 7from . import compat 8from .translations.pgettext_functions import * 9from .model_export import CNV_OT_export_cm3d2_model 10 11 12# メニュー等に項目追加 13def menu_func(self, context): 14 self.layout.operator('object.sync_object_transform' , icon_value=common.kiss_icon()) 15 self.layout.operator('object.align_to_cm3d2_base_bone', icon_value=common.kiss_icon()) 16 17 18@compat.BlRegister() 19class CNV_OT_sync_object_transform(bpy.types.Operator): 20 bl_idname = 'object.sync_object_transform' 21 bl_label = "オブジェクトの位置を合わせる" 22 bl_description = "アクティブオブジェクトの中心位置を、他の選択オブジェクトの中心位置に合わせます" 23 bl_options = {'REGISTER', 'UNDO'} 24 25 @classmethod 26 def poll(cls, context): 27 obs = context.selected_objects 28 return len(obs) == 2 29 30 def execute(self, context): 31 #target_ob = context.active_object 32 #for ob in context.selected_objects: 33 # if target_ob.name != ob.name: 34 # source_ob = ob 35 # break 36 target_ob, source_ob = common.get_target_and_source_object(context) 37 38 if compat.IS_LEGACY: 39 for area in context.screen.areas: 40 if area.type == 'VIEW_3D': 41 for space in area.spaces: 42 if space.type == 'VIEW_3D': 43 target_space = space 44 break 45 46 pre_cursor_location = target_space.cursor_location[:] 47 try: 48 target_space.cursor_location = source_ob.location[:] 49 50 compat.set_select(source_ob, False) 51 bpy.ops.object.origin_set(type='ORIGIN_CURSOR') 52 compat.set_select(source_ob, True) 53 54 finally: 55 target_space.cursor_location = pre_cursor_location[:] 56 else: 57 pre_cursor_loc = context.scene.cursor.location[:] 58 try: 59 context.scene.cursor.location = source_ob.location[:] 60 61 compat.set_select(source_ob, False) 62 bpy.ops.object.origin_set(type='ORIGIN_CURSOR') 63 compat.set_select(source_ob, True) 64 65 finally: 66 context.scene.cursor.location = pre_cursor_loc[:] 67 return {'FINISHED'} 68 69 70 71@compat.BlRegister() 72class CNV_OT_align_to_cm3d2_base_bone(bpy.types.Operator): 73 bl_idname = 'object.align_to_cm3d2_base_bone' 74 bl_label = "Align to Base Bone" 75 bl_description = "Align the object to it's armature's base bone" 76 bl_options = {'REGISTER', 'UNDO'} 77 78 scale = bpy.props.FloatProperty(name="Scale" , default= 5, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="The amount by which the mesh is scaled when imported. Recommended that you use the same when at the time of export.") 79 is_preserve_mesh = bpy.props.BoolProperty (name="Preserve Mesh", default=True, description="Align object transform, then fix mesh transform so it remains in place.") 80 81 items = [ 82 ('ARMATURE' , "Armature" , "", 'OUTLINER_OB_ARMATURE', 1), 83 ('TEXT' , "Text" , "", 'FILE_TEXT' , 2), 84 ('OBJECT_PROPERTY' , "Object Data" , "", 'OBJECT_DATAMODE' , 3), 85 ('ARMATURE_PROPERTY', "Armature Data", "", 'ARMATURE_DATA' , 4), 86 ] 87 bone_info_mode = bpy.props.EnumProperty(items=items, name="Bone Data Source", default='OBJECT_PROPERTY', description="This will decide from where the Bone Data is gathered from.") 88 89 90 @staticmethod 91 def find_base_bone(ob: bpy.types.Object): 92 arm_ob = ob.find_armature() 93 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 94 arm_ob = ob.parent 95 96 base_bone_name = None 97 if arm_ob: 98 base_bone_name = arm_ob.data.get('BaseBone') 99 if not base_bone_name: 100 base_bone_name = ob.data.get('BaseBone') 101 if not base_bone_name: 102 # TODO : Check for base bone in object name 103 # See model_export.CNV_OT_export_cm3d2_model.export() "BoneData情報読み込み" 104 pass 105 106 return base_bone_name 107 108 109 @classmethod 110 def poll(cls, context): 111 ob = context.object 112 if not ob: 113 return False 114 return cls.find_base_bone(ob) != None 115 116 def invoke(self, context, event): 117 ob = context.object 118 119 # model名とか 120 #ob_names = common.remove_serial_number(ob.name, self.is_arrange_name).split('.') 121 #self.model_name = ob_names[0] 122 #self.base_bone_name = ob_names[1] if len(ob_names) >= 2 else 'Auto' 123 124 # ボーン情報元のデフォルトオプションを取得 125 if "BoneData" in context.blend_data.texts: 126 self.bone_info_mode = 'TEXT' 127 if "BoneData:0" in ob: 128 self.bone_info_mode = 'OBJECT_PROPERTY' 129 arm_ob = ob.find_armature() 130 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 131 arm_ob = ob.parent 132 if arm_ob: 133 if "BoneData:0" in arm_ob.data: 134 self.bone_info_mode = 'ARMATURE_PROPERTY' 135 136 self.scale = common.preferences().scale 137 return context.window_manager.invoke_props_dialog(self) 138 139 def draw(self, context): 140 ob = context.object 141 arm_ob = ob.find_armature() 142 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 143 arm_ob = ob.parent 144 145 def _prop_enum_row(layout, data, prop, value, enabled=True): 146 row = layout.row(align=True) 147 name = row.enum_item_name(data, prop, value) 148 icon = row.enum_item_icon(data, prop, value) 149 row.prop_enum(data, prop, value, text=name) 150 row.enabled = enabled 151 return row 152 153 self.layout.prop(self, 'scale') 154 self.layout.prop(self, 'is_preserve_mesh', icon=compat.icon('MESH_DATA')) 155 156 col = self.layout.column(align=True) 157 col.label(text="Bone Data Source", icon='BONE_DATA') 158 _prop_enum_row(col, self, 'bone_info_mode', 'ARMATURE' , enabled=bool(arm_ob )) 159 _prop_enum_row(col, self, 'bone_info_mode', 'TEXT' , enabled=bool("BoneData" in context.blend_data.texts)) 160 _prop_enum_row(col, self, 'bone_info_mode', 'OBJECT_PROPERTY' , enabled=bool("BoneData:0" in ob )) 161 _prop_enum_row(col, self, 'bone_info_mode', 'ARMATURE_PROPERTY', enabled=bool(arm_ob and "BoneData:0" in arm_ob.data)) 162 163 @staticmethod 164 def from_bone_data(ob: bpy.types.Object, bone_data, local_bone_data, base_bone_name, scale=5): 165 166 base_bone_offset = mathutils.Matrix.Identity(4) 167 for bone in local_bone_data: 168 if bone['name'] == base_bone_name: 169 # When the base bone is in the bind pose data, 170 # then the entire mesh needs to be offset from the base bone 171 print("Found base bone in local bone data!") 172 print(bone['matrix']) 173 mat = mathutils.Matrix(np.array(bone['matrix']).reshape((4,4))) 174 mat.transpose() 175 mat.translation *= -scale 176 mat.translation = compat.mul(mat.to_3x3().inverted(), mat.translation) 177 pos = mat.translation.copy() 178 179 mat.transpose() 180 mat.translation = pos 181 #mat.row[3] = (0.0, 0.0, 0.0, 1.0) 182 183 base_bone_offset = mat 184 185 for bone in bone_data: 186 if bone['name'] == base_bone_name: 187 #co = bone['co'].copy() 188 #co.x, co.y, co.z = -co.x, -co.z, co.y 189 #co *= self.scale 190 #ob.location = co 191 # 192 #rot = bone['rot'].copy() 193 #eul = mathutils.Euler((math.radians(90), 0, 0), 'XYZ') 194 #rot.rotate(eul) 195 #ob.rotation_mode = 'QUATERNION' 196 #ob.rotation_quaternion = rot 197 198 parent_mats = [] 199 current_bone = bone 200 while current_bone: 201 local_co_mat = mathutils.Matrix.Translation(mathutils.Vector(current_bone['co']) * scale) 202 local_rot_mat = mathutils.Quaternion(current_bone['rot']).to_matrix().to_4x4() 203 parent_mats.append(compat.mul(local_co_mat, local_rot_mat)) 204 if current_bone.get('parent_name'): 205 for b in bone_data: 206 if b['name'] == current_bone['parent_name']: 207 current_bone = b 208 break 209 elif current_bone.get('parent_index', -1) != -1 : 210 current_bone = bone_data[current_bone['parent_index']] 211 else: 212 current_bone = None 213 214 parent_mats.reverse() 215 mat = mathutils.Matrix() 216 for local_mat in parent_mats: 217 mat = compat.mul(mat, local_mat) 218 219 mat = compat.mul(mat, base_bone_offset.inverted()) 220 221 mat = compat.convert_cm_to_bl_space(mat) 222 mat = compat.convert_cm_to_bl_local_space(mat) 223 ob.matrix_basis = mat 224 break 225 226 227 @staticmethod 228 def from_armature(ob: bpy.types.Object, arm: bpy.types.Armature, base_bone_name): 229 base_bone = arm.bones.get(base_bone_name) 230 mat = base_bone.matrix_local.copy() 231 mat = compat.convert_bl_to_cm_bone_rotation(mat) 232 mat = compat.convert_cm_to_bl_local_space(mat) 233 ob.matrix_basis = mat 234 235 236 def bone_data_report_cancel(self): 237 source_name = self.bl_rna.properties['bone_info_mode'] \ 238 and source_name.enum_items[self.bone_info_mode] \ 239 and source_name.name \ 240 or self.bone_info_mode 241 self.report( 242 type = {'ERROR'}, 243 message = f_tip_( 244 "Could not find 'BaseBone' in {source_name} Please add it or change source", 245 source_name = source_name 246 ) 247 ) 248 return {'CANCELLED'} 249 250 251 def execute(self, context): 252 ob = context.object 253 arm_ob = ob.find_armature() 254 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 255 arm_ob = ob.parent 256 257 base_bone_name = None 258 bone_data = None 259 if self.bone_info_mode == 'ARMATURE': 260 #bone_data = CNV_OT_export_cm3d2_model.armature_bone_data_parser(context, arm_ob) 261 if not 'BaseBone' in arm_ob.data: 262 return bone_data_report_cancel() 263 base_bone_name = arm_ob.data['BaseBone'] 264 if self.bone_info_mode == 'TEXT': 265 bone_data_text = context.blend_data.texts["BoneData"] 266 if not 'BaseBone' in bone_data_text: 267 return bone_data_report_cancel() 268 base_bone_name = bone_data_text['BaseBone'] 269 bone_data = CNV_OT_export_cm3d2_model.bone_data_parser(l.body for l in bone_data_text.lines) 270 local_bone_data = CNV_OT_export_cm3d2_model.local_bone_data_parser(l.body for l in bone_data_text.lines) 271 elif self.bone_info_mode in ['OBJECT_PROPERTY', 'ARMATURE_PROPERTY']: 272 target = ob if self.bone_info_mode == 'OBJECT_PROPERTY' else arm_ob.data 273 if not 'BaseBone' in target: 274 return bone_data_report_cancel() 275 base_bone_name = target['BaseBone'] 276 bone_data = CNV_OT_export_cm3d2_model.bone_data_parser(CNV_OT_export_cm3d2_model.indexed_data_generator(target, prefix="BoneData:")) 277 local_bone_data = CNV_OT_export_cm3d2_model.local_bone_data_parser(CNV_OT_export_cm3d2_model.indexed_data_generator(target, prefix="LocalBoneData:")) 278 279 old_basis = ob.matrix_basis.copy() 280 if bone_data: 281 self.from_bone_data(ob, bone_data, local_bone_data, base_bone_name, self.scale) 282 else: 283 self.from_armature(ob, arm_ob.data, base_bone_name) 284 285 if self.is_preserve_mesh: 286 new_basis = ob.matrix_basis.copy() 287 ob.matrix_basis = compat.mul(new_basis.inverted(), old_basis) 288 bpy.ops.object.transform_apply(location=True, rotation=True, scale=False) 289 ob.matrix_basis = new_basis 290 291 292 return {'FINISHED'} 293 294
@compat.BlRegister()
class
CNV_OT_sync_object_transform19@compat.BlRegister() 20class CNV_OT_sync_object_transform(bpy.types.Operator): 21 bl_idname = 'object.sync_object_transform' 22 bl_label = "オブジェクトの位置を合わせる" 23 bl_description = "アクティブオブジェクトの中心位置を、他の選択オブジェクトの中心位置に合わせます" 24 bl_options = {'REGISTER', 'UNDO'} 25 26 @classmethod 27 def poll(cls, context): 28 obs = context.selected_objects 29 return len(obs) == 2 30 31 def execute(self, context): 32 #target_ob = context.active_object 33 #for ob in context.selected_objects: 34 # if target_ob.name != ob.name: 35 # source_ob = ob 36 # break 37 target_ob, source_ob = common.get_target_and_source_object(context) 38 39 if compat.IS_LEGACY: 40 for area in context.screen.areas: 41 if area.type == 'VIEW_3D': 42 for space in area.spaces: 43 if space.type == 'VIEW_3D': 44 target_space = space 45 break 46 47 pre_cursor_location = target_space.cursor_location[:] 48 try: 49 target_space.cursor_location = source_ob.location[:] 50 51 compat.set_select(source_ob, False) 52 bpy.ops.object.origin_set(type='ORIGIN_CURSOR') 53 compat.set_select(source_ob, True) 54 55 finally: 56 target_space.cursor_location = pre_cursor_location[:] 57 else: 58 pre_cursor_loc = context.scene.cursor.location[:] 59 try: 60 context.scene.cursor.location = source_ob.location[:] 61 62 compat.set_select(source_ob, False) 63 bpy.ops.object.origin_set(type='ORIGIN_CURSOR') 64 compat.set_select(source_ob, True) 65 66 finally: 67 context.scene.cursor.location = pre_cursor_loc[:] 68 return {'FINISHED'}
def
execute(self, context):
31 def execute(self, context): 32 #target_ob = context.active_object 33 #for ob in context.selected_objects: 34 # if target_ob.name != ob.name: 35 # source_ob = ob 36 # break 37 target_ob, source_ob = common.get_target_and_source_object(context) 38 39 if compat.IS_LEGACY: 40 for area in context.screen.areas: 41 if area.type == 'VIEW_3D': 42 for space in area.spaces: 43 if space.type == 'VIEW_3D': 44 target_space = space 45 break 46 47 pre_cursor_location = target_space.cursor_location[:] 48 try: 49 target_space.cursor_location = source_ob.location[:] 50 51 compat.set_select(source_ob, False) 52 bpy.ops.object.origin_set(type='ORIGIN_CURSOR') 53 compat.set_select(source_ob, True) 54 55 finally: 56 target_space.cursor_location = pre_cursor_location[:] 57 else: 58 pre_cursor_loc = context.scene.cursor.location[:] 59 try: 60 context.scene.cursor.location = source_ob.location[:] 61 62 compat.set_select(source_ob, False) 63 bpy.ops.object.origin_set(type='ORIGIN_CURSOR') 64 compat.set_select(source_ob, True) 65 66 finally: 67 context.scene.cursor.location = pre_cursor_loc[:] 68 return {'FINISHED'}
Inherited Members
- bpy_types.Operator
- as_keywords
- poll_message_set
- builtins.bpy_struct
- keys
- values
- items
- get
- pop
- as_pointer
- keyframe_insert
- keyframe_delete
- driver_add
- driver_remove
- is_property_set
- property_unset
- is_property_readonly
- is_property_overridable_library
- property_overridable_library_set
- path_resolve
- path_from_id
- type_recast
- bl_rna_get_subclass_py
- bl_rna_get_subclass
- id_properties_ensure
- id_properties_clear
- id_properties_ui
- id_data
@compat.BlRegister()
class
CNV_OT_align_to_cm3d2_base_bone72@compat.BlRegister() 73class CNV_OT_align_to_cm3d2_base_bone(bpy.types.Operator): 74 bl_idname = 'object.align_to_cm3d2_base_bone' 75 bl_label = "Align to Base Bone" 76 bl_description = "Align the object to it's armature's base bone" 77 bl_options = {'REGISTER', 'UNDO'} 78 79 scale = bpy.props.FloatProperty(name="Scale" , default= 5, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="The amount by which the mesh is scaled when imported. Recommended that you use the same when at the time of export.") 80 is_preserve_mesh = bpy.props.BoolProperty (name="Preserve Mesh", default=True, description="Align object transform, then fix mesh transform so it remains in place.") 81 82 items = [ 83 ('ARMATURE' , "Armature" , "", 'OUTLINER_OB_ARMATURE', 1), 84 ('TEXT' , "Text" , "", 'FILE_TEXT' , 2), 85 ('OBJECT_PROPERTY' , "Object Data" , "", 'OBJECT_DATAMODE' , 3), 86 ('ARMATURE_PROPERTY', "Armature Data", "", 'ARMATURE_DATA' , 4), 87 ] 88 bone_info_mode = bpy.props.EnumProperty(items=items, name="Bone Data Source", default='OBJECT_PROPERTY', description="This will decide from where the Bone Data is gathered from.") 89 90 91 @staticmethod 92 def find_base_bone(ob: bpy.types.Object): 93 arm_ob = ob.find_armature() 94 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 95 arm_ob = ob.parent 96 97 base_bone_name = None 98 if arm_ob: 99 base_bone_name = arm_ob.data.get('BaseBone') 100 if not base_bone_name: 101 base_bone_name = ob.data.get('BaseBone') 102 if not base_bone_name: 103 # TODO : Check for base bone in object name 104 # See model_export.CNV_OT_export_cm3d2_model.export() "BoneData情報読み込み" 105 pass 106 107 return base_bone_name 108 109 110 @classmethod 111 def poll(cls, context): 112 ob = context.object 113 if not ob: 114 return False 115 return cls.find_base_bone(ob) != None 116 117 def invoke(self, context, event): 118 ob = context.object 119 120 # model名とか 121 #ob_names = common.remove_serial_number(ob.name, self.is_arrange_name).split('.') 122 #self.model_name = ob_names[0] 123 #self.base_bone_name = ob_names[1] if len(ob_names) >= 2 else 'Auto' 124 125 # ボーン情報元のデフォルトオプションを取得 126 if "BoneData" in context.blend_data.texts: 127 self.bone_info_mode = 'TEXT' 128 if "BoneData:0" in ob: 129 self.bone_info_mode = 'OBJECT_PROPERTY' 130 arm_ob = ob.find_armature() 131 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 132 arm_ob = ob.parent 133 if arm_ob: 134 if "BoneData:0" in arm_ob.data: 135 self.bone_info_mode = 'ARMATURE_PROPERTY' 136 137 self.scale = common.preferences().scale 138 return context.window_manager.invoke_props_dialog(self) 139 140 def draw(self, context): 141 ob = context.object 142 arm_ob = ob.find_armature() 143 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 144 arm_ob = ob.parent 145 146 def _prop_enum_row(layout, data, prop, value, enabled=True): 147 row = layout.row(align=True) 148 name = row.enum_item_name(data, prop, value) 149 icon = row.enum_item_icon(data, prop, value) 150 row.prop_enum(data, prop, value, text=name) 151 row.enabled = enabled 152 return row 153 154 self.layout.prop(self, 'scale') 155 self.layout.prop(self, 'is_preserve_mesh', icon=compat.icon('MESH_DATA')) 156 157 col = self.layout.column(align=True) 158 col.label(text="Bone Data Source", icon='BONE_DATA') 159 _prop_enum_row(col, self, 'bone_info_mode', 'ARMATURE' , enabled=bool(arm_ob )) 160 _prop_enum_row(col, self, 'bone_info_mode', 'TEXT' , enabled=bool("BoneData" in context.blend_data.texts)) 161 _prop_enum_row(col, self, 'bone_info_mode', 'OBJECT_PROPERTY' , enabled=bool("BoneData:0" in ob )) 162 _prop_enum_row(col, self, 'bone_info_mode', 'ARMATURE_PROPERTY', enabled=bool(arm_ob and "BoneData:0" in arm_ob.data)) 163 164 @staticmethod 165 def from_bone_data(ob: bpy.types.Object, bone_data, local_bone_data, base_bone_name, scale=5): 166 167 base_bone_offset = mathutils.Matrix.Identity(4) 168 for bone in local_bone_data: 169 if bone['name'] == base_bone_name: 170 # When the base bone is in the bind pose data, 171 # then the entire mesh needs to be offset from the base bone 172 print("Found base bone in local bone data!") 173 print(bone['matrix']) 174 mat = mathutils.Matrix(np.array(bone['matrix']).reshape((4,4))) 175 mat.transpose() 176 mat.translation *= -scale 177 mat.translation = compat.mul(mat.to_3x3().inverted(), mat.translation) 178 pos = mat.translation.copy() 179 180 mat.transpose() 181 mat.translation = pos 182 #mat.row[3] = (0.0, 0.0, 0.0, 1.0) 183 184 base_bone_offset = mat 185 186 for bone in bone_data: 187 if bone['name'] == base_bone_name: 188 #co = bone['co'].copy() 189 #co.x, co.y, co.z = -co.x, -co.z, co.y 190 #co *= self.scale 191 #ob.location = co 192 # 193 #rot = bone['rot'].copy() 194 #eul = mathutils.Euler((math.radians(90), 0, 0), 'XYZ') 195 #rot.rotate(eul) 196 #ob.rotation_mode = 'QUATERNION' 197 #ob.rotation_quaternion = rot 198 199 parent_mats = [] 200 current_bone = bone 201 while current_bone: 202 local_co_mat = mathutils.Matrix.Translation(mathutils.Vector(current_bone['co']) * scale) 203 local_rot_mat = mathutils.Quaternion(current_bone['rot']).to_matrix().to_4x4() 204 parent_mats.append(compat.mul(local_co_mat, local_rot_mat)) 205 if current_bone.get('parent_name'): 206 for b in bone_data: 207 if b['name'] == current_bone['parent_name']: 208 current_bone = b 209 break 210 elif current_bone.get('parent_index', -1) != -1 : 211 current_bone = bone_data[current_bone['parent_index']] 212 else: 213 current_bone = None 214 215 parent_mats.reverse() 216 mat = mathutils.Matrix() 217 for local_mat in parent_mats: 218 mat = compat.mul(mat, local_mat) 219 220 mat = compat.mul(mat, base_bone_offset.inverted()) 221 222 mat = compat.convert_cm_to_bl_space(mat) 223 mat = compat.convert_cm_to_bl_local_space(mat) 224 ob.matrix_basis = mat 225 break 226 227 228 @staticmethod 229 def from_armature(ob: bpy.types.Object, arm: bpy.types.Armature, base_bone_name): 230 base_bone = arm.bones.get(base_bone_name) 231 mat = base_bone.matrix_local.copy() 232 mat = compat.convert_bl_to_cm_bone_rotation(mat) 233 mat = compat.convert_cm_to_bl_local_space(mat) 234 ob.matrix_basis = mat 235 236 237 def bone_data_report_cancel(self): 238 source_name = self.bl_rna.properties['bone_info_mode'] \ 239 and source_name.enum_items[self.bone_info_mode] \ 240 and source_name.name \ 241 or self.bone_info_mode 242 self.report( 243 type = {'ERROR'}, 244 message = f_tip_( 245 "Could not find 'BaseBone' in {source_name} Please add it or change source", 246 source_name = source_name 247 ) 248 ) 249 return {'CANCELLED'} 250 251 252 def execute(self, context): 253 ob = context.object 254 arm_ob = ob.find_armature() 255 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 256 arm_ob = ob.parent 257 258 base_bone_name = None 259 bone_data = None 260 if self.bone_info_mode == 'ARMATURE': 261 #bone_data = CNV_OT_export_cm3d2_model.armature_bone_data_parser(context, arm_ob) 262 if not 'BaseBone' in arm_ob.data: 263 return bone_data_report_cancel() 264 base_bone_name = arm_ob.data['BaseBone'] 265 if self.bone_info_mode == 'TEXT': 266 bone_data_text = context.blend_data.texts["BoneData"] 267 if not 'BaseBone' in bone_data_text: 268 return bone_data_report_cancel() 269 base_bone_name = bone_data_text['BaseBone'] 270 bone_data = CNV_OT_export_cm3d2_model.bone_data_parser(l.body for l in bone_data_text.lines) 271 local_bone_data = CNV_OT_export_cm3d2_model.local_bone_data_parser(l.body for l in bone_data_text.lines) 272 elif self.bone_info_mode in ['OBJECT_PROPERTY', 'ARMATURE_PROPERTY']: 273 target = ob if self.bone_info_mode == 'OBJECT_PROPERTY' else arm_ob.data 274 if not 'BaseBone' in target: 275 return bone_data_report_cancel() 276 base_bone_name = target['BaseBone'] 277 bone_data = CNV_OT_export_cm3d2_model.bone_data_parser(CNV_OT_export_cm3d2_model.indexed_data_generator(target, prefix="BoneData:")) 278 local_bone_data = CNV_OT_export_cm3d2_model.local_bone_data_parser(CNV_OT_export_cm3d2_model.indexed_data_generator(target, prefix="LocalBoneData:")) 279 280 old_basis = ob.matrix_basis.copy() 281 if bone_data: 282 self.from_bone_data(ob, bone_data, local_bone_data, base_bone_name, self.scale) 283 else: 284 self.from_armature(ob, arm_ob.data, base_bone_name) 285 286 if self.is_preserve_mesh: 287 new_basis = ob.matrix_basis.copy() 288 ob.matrix_basis = compat.mul(new_basis.inverted(), old_basis) 289 bpy.ops.object.transform_apply(location=True, rotation=True, scale=False) 290 ob.matrix_basis = new_basis 291 292 293 return {'FINISHED'}
scale: <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Scale', 'default': 5, 'min': 0.1, 'max': 100, 'soft_min': 0.1, 'soft_max': 100, 'step': 100, 'precision': 1, 'description': 'The amount by which the mesh is scaled when imported. Recommended that you use the same when at the time of export.', 'attr': 'scale'}> =
<_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Scale', 'default': 5, 'min': 0.1, 'max': 100, 'soft_min': 0.1, 'soft_max': 100, 'step': 100, 'precision': 1, 'description': 'The amount by which the mesh is scaled when imported. Recommended that you use the same when at the time of export.', 'attr': 'scale'}>
is_preserve_mesh: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Preserve Mesh', 'default': True, 'description': 'Align object transform, then fix mesh transform so it remains in place.', 'attr': 'is_preserve_mesh'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Preserve Mesh', 'default': True, 'description': 'Align object transform, then fix mesh transform so it remains in place.', 'attr': 'is_preserve_mesh'}>
items =
[('ARMATURE', 'Armature', '', 'OUTLINER_OB_ARMATURE', 1), ('TEXT', 'Text', '', 'FILE_TEXT', 2), ('OBJECT_PROPERTY', 'Object Data', '', 'OBJECT_DATAMODE', 3), ('ARMATURE_PROPERTY', 'Armature Data', '', 'ARMATURE_DATA', 4)]
bone_info_mode: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ARMATURE', 'Armature', '', 'OUTLINER_OB_ARMATURE', 1), ('TEXT', 'Text', '', 'FILE_TEXT', 2), ('OBJECT_PROPERTY', 'Object Data', '', 'OBJECT_DATAMODE', 3), ('ARMATURE_PROPERTY', 'Armature Data', '', 'ARMATURE_DATA', 4)], 'name': 'Bone Data Source', 'default': 'OBJECT_PROPERTY', 'description': 'This will decide from where the Bone Data is gathered from.', 'attr': 'bone_info_mode'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ARMATURE', 'Armature', '', 'OUTLINER_OB_ARMATURE', 1), ('TEXT', 'Text', '', 'FILE_TEXT', 2), ('OBJECT_PROPERTY', 'Object Data', '', 'OBJECT_DATAMODE', 3), ('ARMATURE_PROPERTY', 'Armature Data', '', 'ARMATURE_DATA', 4)], 'name': 'Bone Data Source', 'default': 'OBJECT_PROPERTY', 'description': 'This will decide from where the Bone Data is gathered from.', 'attr': 'bone_info_mode'}>
@staticmethod
def
find_base_bone(ob: bpy_types.Object):
91 @staticmethod 92 def find_base_bone(ob: bpy.types.Object): 93 arm_ob = ob.find_armature() 94 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 95 arm_ob = ob.parent 96 97 base_bone_name = None 98 if arm_ob: 99 base_bone_name = arm_ob.data.get('BaseBone') 100 if not base_bone_name: 101 base_bone_name = ob.data.get('BaseBone') 102 if not base_bone_name: 103 # TODO : Check for base bone in object name 104 # See model_export.CNV_OT_export_cm3d2_model.export() "BoneData情報読み込み" 105 pass 106 107 return base_bone_name
def
invoke(self, context, event):
117 def invoke(self, context, event): 118 ob = context.object 119 120 # model名とか 121 #ob_names = common.remove_serial_number(ob.name, self.is_arrange_name).split('.') 122 #self.model_name = ob_names[0] 123 #self.base_bone_name = ob_names[1] if len(ob_names) >= 2 else 'Auto' 124 125 # ボーン情報元のデフォルトオプションを取得 126 if "BoneData" in context.blend_data.texts: 127 self.bone_info_mode = 'TEXT' 128 if "BoneData:0" in ob: 129 self.bone_info_mode = 'OBJECT_PROPERTY' 130 arm_ob = ob.find_armature() 131 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 132 arm_ob = ob.parent 133 if arm_ob: 134 if "BoneData:0" in arm_ob.data: 135 self.bone_info_mode = 'ARMATURE_PROPERTY' 136 137 self.scale = common.preferences().scale 138 return context.window_manager.invoke_props_dialog(self)
def
draw(self, context):
140 def draw(self, context): 141 ob = context.object 142 arm_ob = ob.find_armature() 143 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 144 arm_ob = ob.parent 145 146 def _prop_enum_row(layout, data, prop, value, enabled=True): 147 row = layout.row(align=True) 148 name = row.enum_item_name(data, prop, value) 149 icon = row.enum_item_icon(data, prop, value) 150 row.prop_enum(data, prop, value, text=name) 151 row.enabled = enabled 152 return row 153 154 self.layout.prop(self, 'scale') 155 self.layout.prop(self, 'is_preserve_mesh', icon=compat.icon('MESH_DATA')) 156 157 col = self.layout.column(align=True) 158 col.label(text="Bone Data Source", icon='BONE_DATA') 159 _prop_enum_row(col, self, 'bone_info_mode', 'ARMATURE' , enabled=bool(arm_ob )) 160 _prop_enum_row(col, self, 'bone_info_mode', 'TEXT' , enabled=bool("BoneData" in context.blend_data.texts)) 161 _prop_enum_row(col, self, 'bone_info_mode', 'OBJECT_PROPERTY' , enabled=bool("BoneData:0" in ob )) 162 _prop_enum_row(col, self, 'bone_info_mode', 'ARMATURE_PROPERTY', enabled=bool(arm_ob and "BoneData:0" in arm_ob.data))
@staticmethod
def
from_bone_data( ob: bpy_types.Object, bone_data, local_bone_data, base_bone_name, scale=5):
164 @staticmethod 165 def from_bone_data(ob: bpy.types.Object, bone_data, local_bone_data, base_bone_name, scale=5): 166 167 base_bone_offset = mathutils.Matrix.Identity(4) 168 for bone in local_bone_data: 169 if bone['name'] == base_bone_name: 170 # When the base bone is in the bind pose data, 171 # then the entire mesh needs to be offset from the base bone 172 print("Found base bone in local bone data!") 173 print(bone['matrix']) 174 mat = mathutils.Matrix(np.array(bone['matrix']).reshape((4,4))) 175 mat.transpose() 176 mat.translation *= -scale 177 mat.translation = compat.mul(mat.to_3x3().inverted(), mat.translation) 178 pos = mat.translation.copy() 179 180 mat.transpose() 181 mat.translation = pos 182 #mat.row[3] = (0.0, 0.0, 0.0, 1.0) 183 184 base_bone_offset = mat 185 186 for bone in bone_data: 187 if bone['name'] == base_bone_name: 188 #co = bone['co'].copy() 189 #co.x, co.y, co.z = -co.x, -co.z, co.y 190 #co *= self.scale 191 #ob.location = co 192 # 193 #rot = bone['rot'].copy() 194 #eul = mathutils.Euler((math.radians(90), 0, 0), 'XYZ') 195 #rot.rotate(eul) 196 #ob.rotation_mode = 'QUATERNION' 197 #ob.rotation_quaternion = rot 198 199 parent_mats = [] 200 current_bone = bone 201 while current_bone: 202 local_co_mat = mathutils.Matrix.Translation(mathutils.Vector(current_bone['co']) * scale) 203 local_rot_mat = mathutils.Quaternion(current_bone['rot']).to_matrix().to_4x4() 204 parent_mats.append(compat.mul(local_co_mat, local_rot_mat)) 205 if current_bone.get('parent_name'): 206 for b in bone_data: 207 if b['name'] == current_bone['parent_name']: 208 current_bone = b 209 break 210 elif current_bone.get('parent_index', -1) != -1 : 211 current_bone = bone_data[current_bone['parent_index']] 212 else: 213 current_bone = None 214 215 parent_mats.reverse() 216 mat = mathutils.Matrix() 217 for local_mat in parent_mats: 218 mat = compat.mul(mat, local_mat) 219 220 mat = compat.mul(mat, base_bone_offset.inverted()) 221 222 mat = compat.convert_cm_to_bl_space(mat) 223 mat = compat.convert_cm_to_bl_local_space(mat) 224 ob.matrix_basis = mat 225 break
@staticmethod
def
from_armature(ob: bpy_types.Object, arm: bpy.types.Armature, base_bone_name):
228 @staticmethod 229 def from_armature(ob: bpy.types.Object, arm: bpy.types.Armature, base_bone_name): 230 base_bone = arm.bones.get(base_bone_name) 231 mat = base_bone.matrix_local.copy() 232 mat = compat.convert_bl_to_cm_bone_rotation(mat) 233 mat = compat.convert_cm_to_bl_local_space(mat) 234 ob.matrix_basis = mat
def
bone_data_report_cancel(self):
237 def bone_data_report_cancel(self): 238 source_name = self.bl_rna.properties['bone_info_mode'] \ 239 and source_name.enum_items[self.bone_info_mode] \ 240 and source_name.name \ 241 or self.bone_info_mode 242 self.report( 243 type = {'ERROR'}, 244 message = f_tip_( 245 "Could not find 'BaseBone' in {source_name} Please add it or change source", 246 source_name = source_name 247 ) 248 ) 249 return {'CANCELLED'}
def
execute(self, context):
252 def execute(self, context): 253 ob = context.object 254 arm_ob = ob.find_armature() 255 if (not arm_ob) and (ob.parent and ob.parent.type == 'ARMATURE'): 256 arm_ob = ob.parent 257 258 base_bone_name = None 259 bone_data = None 260 if self.bone_info_mode == 'ARMATURE': 261 #bone_data = CNV_OT_export_cm3d2_model.armature_bone_data_parser(context, arm_ob) 262 if not 'BaseBone' in arm_ob.data: 263 return bone_data_report_cancel() 264 base_bone_name = arm_ob.data['BaseBone'] 265 if self.bone_info_mode == 'TEXT': 266 bone_data_text = context.blend_data.texts["BoneData"] 267 if not 'BaseBone' in bone_data_text: 268 return bone_data_report_cancel() 269 base_bone_name = bone_data_text['BaseBone'] 270 bone_data = CNV_OT_export_cm3d2_model.bone_data_parser(l.body for l in bone_data_text.lines) 271 local_bone_data = CNV_OT_export_cm3d2_model.local_bone_data_parser(l.body for l in bone_data_text.lines) 272 elif self.bone_info_mode in ['OBJECT_PROPERTY', 'ARMATURE_PROPERTY']: 273 target = ob if self.bone_info_mode == 'OBJECT_PROPERTY' else arm_ob.data 274 if not 'BaseBone' in target: 275 return bone_data_report_cancel() 276 base_bone_name = target['BaseBone'] 277 bone_data = CNV_OT_export_cm3d2_model.bone_data_parser(CNV_OT_export_cm3d2_model.indexed_data_generator(target, prefix="BoneData:")) 278 local_bone_data = CNV_OT_export_cm3d2_model.local_bone_data_parser(CNV_OT_export_cm3d2_model.indexed_data_generator(target, prefix="LocalBoneData:")) 279 280 old_basis = ob.matrix_basis.copy() 281 if bone_data: 282 self.from_bone_data(ob, bone_data, local_bone_data, base_bone_name, self.scale) 283 else: 284 self.from_armature(ob, arm_ob.data, base_bone_name) 285 286 if self.is_preserve_mesh: 287 new_basis = ob.matrix_basis.copy() 288 ob.matrix_basis = compat.mul(new_basis.inverted(), old_basis) 289 bpy.ops.object.transform_apply(location=True, rotation=True, scale=False) 290 ob.matrix_basis = new_basis 291 292 293 return {'FINISHED'}
Inherited Members
- bpy_types.Operator
- as_keywords
- poll_message_set
- builtins.bpy_struct
- keys
- values
- get
- pop
- as_pointer
- keyframe_insert
- keyframe_delete
- driver_add
- driver_remove
- is_property_set
- property_unset
- is_property_readonly
- is_property_overridable_library
- property_overridable_library_set
- path_resolve
- path_from_id
- type_recast
- bl_rna_get_subclass_py
- bl_rna_get_subclass
- id_properties_ensure
- id_properties_clear
- id_properties_ui
- id_data